#include <iostream>
#include <log4cpp/Appender.hh>
#include <log4cpp/OstreamAppender.hh>
#include <log4cpp/FileAppender.hh>
#include <log4cpp/PatternLayout.hh>
#include <log4cpp/Category.hh>
using namespace std;
using namespace log4cpp;

// 日志宏：自动填充文件名(__FILE__)、行号(__LINE__)、函数名(__FUNCTION__)
#define LOG_WARN(msg) Logger::getInstance()->warn(__FILE__,__LINE__,__FUNCTION__,msg)
#define LOG_ERROR(msg) Logger::getInstance()->error(__FILE__,__LINE__,__FUNCTION__,msg)
#define LOG_DEBUG(msg) Logger::getInstance()->debug(__FILE__,__LINE__,__FUNCTION__,msg)
#define LOG_INFO(msg) Logger::getInstance()->info(__FILE__,__LINE__,__FUNCTION__,msg)

class Logger{
public:
    void warn(const char * file, int line, const char * func, const char * msg);
    void error(const char * file, int line, const char * func, const char * msg);
    void debug(const char * file, int line, const char * func, const char * msg);
    void info(const char * file, int line, const char * func, const char * msg);

    static Logger * getInstance();

    static void destroy();

private:
    // 1. appenders的初始化与析构
    Logger();
    ~Logger();

    // 2. 公共布局对象与公共初始化方法
    PatternLayout* _commonLayout;
    void initAppender(log4cpp::LayoutAppender* appender);
    void initConsoleAppender();
    void initFileAppender(const string& filename);
    
    // 3. 数据成员
    static Logger *_pInstance;  // 单例实例指针
    Category *_root;            // 根日志类别

    // 4. 禁止拷贝与重载赋值运算符
    Logger(const Logger &) = delete;
    Logger & operator=(const Logger &) = delete;
};

// 对象指针
Logger* Logger::_pInstance = nullptr;

// 返回单例实例（首次调用时创建）
Logger* Logger::getInstance(){
    if(!_pInstance){
        _pInstance = new Logger();
    }

    return _pInstance;
}

// 销毁单例实例并释放资源（需手动调用，防止内存泄漏）
void Logger::destroy(){
    if(_pInstance){
        delete _pInstance;
        _pInstance = nullptr;
    }
}

// 私有构造函数，初始化日志系统，创建控制台+文件appender
Logger::Logger() {
    _root = &Category::getInstance("MyLogger");
    
    // 1. 初始化公共布局
    initConsoleAppender();
    initFileAppender("mylog.log");

    _root->setPriority(Priority::DEBUG);
}

// 清理所有appender资源（注意：不会销毁单例实例，需手动调用destroy()）
Logger::~Logger(){
    if(_root){
        _root->removeAllAppenders();
    }
}

void Logger::initConsoleAppender() {
    OstreamAppender* app = new OstreamAppender("console", &std::cout);
    PatternLayout* layout = new PatternLayout();
    layout->setConversionPattern("%d %c [%p] %m%n");
    app->setLayout(layout);
    _root->addAppender(app);
}

void Logger::initFileAppender(const string& filename) {
    FileAppender* app = new FileAppender("file", filename);
    PatternLayout* layout = new PatternLayout();
    layout->setConversionPattern("%d %c [%p] %m%n");
    app->setLayout(layout);
    _root->addAppender(app);
}

void Logger::warn(const char * file, int line, const char * func, const char * msg){
//    _root->setPriority(Priority::WARN);
    _root->warn("[%s:%d %s] %s", file, line, func, msg);
}

void Logger::error(const char * file, int line, const char * func, const char * msg){
//    _root->setPriority(Priority::ERROR);
    _root->error("[%s:%d %s] %s", file, line, func, msg);
}

void Logger::debug(const char * file, int line, const char * func, const char * msg){
//    _root->setPriority(Priority::DEBUG);
    _root->debug("[%s:%d %s] %s", file, line, func, msg);
}

void Logger::info(const char * file, int line, const char * func, const char * msg){
//    _root->setPriority(Priority::INFO);
    _root->info("[%s:%d %s] %s", file, line, func, msg);
}

int main(){   
//    Logger* logger = Logger::getInstance();
//    logger->warn(__FILE__, __LINE__, __func__, "测试警告信息");

    LOG_WARN("test warn");
    LOG_INFO("test info");
    LOG_DEBUG("test debug");
    LOG_ERROR("test error");
    Logger::destroy();

    return 0;
}

